1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.image; 12 public import hip.api.data.image; 13 14 15 IHipBMPDecoder bmp; 16 IHipJPEGDecoder jpeg; 17 IHipPNGDecoder png; 18 IHipWebPDecoder webP; 19 20 21 public class HipImageImpl : IImage 22 { 23 IHipImageDecoder decoder; 24 string imagePath; 25 int width, height; 26 ubyte bytesPerPixel; 27 ushort bitsPerPixel; 28 29 ubyte[] pixels; 30 this(string path = "") 31 { 32 import hip.image_backend.impl; 33 imagePath = path; 34 decoder = getDecoder(path); 35 } 36 37 static immutable(IImage) getPixelImage() 38 { 39 __gshared HipImageImpl img; 40 __gshared ubyte[4] pixel = IHipImageDecoder.getPixel(); 41 if(img is null) 42 { 43 img = new HipImageImpl("Pixel"); 44 img.pixels = pixel; 45 img.width = 1; 46 img.height = 1; 47 img.bytesPerPixel = 4; 48 } 49 return cast(immutable)img; 50 } 51 string getName() const {return imagePath;} 52 uint getWidth() const {return width;} 53 uint getHeight() const {return height;} 54 ubyte getBytesPerPixel() const {return bytesPerPixel;} 55 const(ubyte[]) getPalette() const {return decoder.getPalette;} 56 const(ubyte[]) getPixels() const {return pixels;} 57 58 void loadRaw(in ubyte[] pixels, int width, int height, ubyte bytesPerPixel) 59 { 60 this.width = width; 61 this.height = height; 62 this.pixels = cast(ubyte[])pixels; 63 this.bytesPerPixel = bytesPerPixel; 64 this.bitsPerPixel = cast(ubyte)(bytesPerPixel*8); 65 } 66 67 68 bool loadFromMemory(ubyte[] data, void delegate(IImage self) onSuccess, void delegate() onFailure) 69 { 70 import hip.error.handler; 71 if(ErrorHandler.assertErrorMessage(data.length != 0, "No data was passed to load Image.", "Could not load image")) 72 return false; 73 if(ErrorHandler.assertLazyErrorMessage(decoder.startDecoding(data, () 74 { 75 width = decoder.getWidth(); 76 height = decoder.getHeight(); 77 bitsPerPixel = decoder.getBitsPerPixel(); 78 bytesPerPixel = decoder.getBytesPerPixel(); 79 pixels = cast(ubyte[])decoder.getPixels(); 80 onSuccess(this); 81 }, onFailure), 82 "Decoding Image: ", "Could not load image " ~ imagePath)) 83 return false; 84 85 return true; 86 } 87 88 bool hasLoadedData() const {return pixels !is null && width != 0 && height != 0;} 89 90 ubyte[] monochromeToRGBA() const 91 { 92 import hip.error.handler; 93 ubyte[] pix = new ubyte[](4*width*height); //RGBA for each pixel 94 ErrorHandler.assertExit(pix != null, "Out of memory when converting monochrome to RGBA"); 95 uint pixelsLength = width*height; 96 ubyte color; 97 uint z; 98 for(uint i = 0; i < pixelsLength; i++) 99 { 100 //Palette r color = palette[pixels[i]*4] 101 color = (cast(ubyte*)pixels)[i]; 102 pix[z++] = color; //R 103 pix[z++] = color; //G 104 pix[z++] = color; //B 105 pix[z++] = color; //A 106 } 107 108 return pix; 109 } 110 111 ubyte[] convertPalettizedToRGBA() const 112 { 113 import hip.error.handler; 114 ubyte[] pix = new ubyte[](4*width*height); //RGBA for each pixel 115 ErrorHandler.assertExit(pix != null, "Out of memory when converting palette pixels to RGBA"); 116 117 uint pixelsLength = width*height; 118 const(ubyte[]) palette = decoder.getPalette(); 119 120 uint colorIndex; 121 uint z; 122 for(uint i = 0; i < pixelsLength; i++) 123 { 124 //Palette r color = palette[pixels[i]*4] 125 colorIndex = (cast(ubyte*)pixels)[i]*4; 126 pix[z++] = palette[colorIndex]; //R 127 pix[z++] = palette[colorIndex+1]; //G 128 pix[z++] = palette[colorIndex+2]; //B 129 pix[z++] = palette[colorIndex+3]; //A 130 } 131 132 return pix; 133 } 134 135 void dispose() 136 { 137 decoder.dispose(); 138 } 139 alias w = width; 140 alias h = height; 141 } 142 143